package com.forage.exp.config;

import com.forage.exp.constant.GlobalErrorEnum;
import com.forage.exp.constant.ResponseStatusEnum;
import com.forage.exp.filter.JwtAuthenticationTokenFilter;
import com.forage.exp.po.GlobalException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.servlet.HandlerExceptionResolver;
import top.iceclean.logtrace.annotation.EnableLogTrace;
import top.iceclean.logtrace.bean.Logger;

/**
 * @author : Ice'Clean
 * @date : 2022-05-03
 */
//@EnableLogTrace
@Slf4j
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private Logger logTrace;

    /**
     * 返回的密码暂时不加密
     * @return 密码加密解析器
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        //创建BCryptPasswordEncoder注入容器
//        return new BCryptPasswordEncoder();

        return new PasswordEncoder() {
            @Override
            public String encode(CharSequence rawPassword) {
                return rawPassword.toString();//加密
            }
            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                return rawPassword.toString().equals(encodedPassword);//解析
            }
        };
    }

    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Autowired
    @Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver resolver;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http    //关闭csrf
                .csrf().disable()
                //不通过Session获取SecurityContext
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                //允许跨域
                .and().cors();

        http
                .authorizeRequests()
                // 允许匿名访问的接口
                .antMatchers("/test","/user/login","/log/**","/css/**","/js/**").anonymous();
        // 除上面外的所有请求全部需要鉴权认证
//                .anyRequest().authenticated();
//                .anyRequest().anonymous();

        http    //添加过滤器
                .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        http    //添加异常处理器
                .exceptionHandling()
                .authenticationEntryPoint((request, response, authenticationException) -> {
                    log.error("认证异常处理器启动");
                    if (authenticationException instanceof InsufficientAuthenticationException){
                        resolver.resolveException(request,response, null,
                                new GlobalException(GlobalErrorEnum.AUTHENTICATION_EXCEPTION, "未携带JWT码访问"));
                        return;
                    }
                    resolver.resolveException(request,response, null,authenticationException);
                })
                .accessDeniedHandler((request, response, accessDeniedException) -> {
                    log.error("权限异常处理器启动");
                    resolver.resolveException(request,response, null,accessDeniedException);
                });
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
